// mtpinterface.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "MTPconnect.h"
#include "PortDevEventCallback.h"

#define MTP_CONNECTED 1
#define GUI_CONNECTED 2
#define IN_PROP 4

enum PREFIX { COMMAND, FILE_AUD, FILE_VID, FILE_PIC, FILE_XML, PROP_NAME, FILE_TXT, DELETE_FILE, DELETE_PROP, RENAME_PROP, COPY_ALL_DATA };
enum COMMAND_TYPE { COPY, END_COPY, END_PROP, QUIT, DEV_DISCONNECT, DEV_CONNECT, TMP_XML_PATH, FILE_EXISTS, AUDIO_SCRIPT, COPY_ALL_COMPLETE };

uint8_t state = 0;
LPWSTR curPropID = NULL;
LPWSTR arID = NULL;

/**
    Split up the prop name and some path
    [in] in - string in form of [prop name]/[path/to/some/file]
    [out] prop - prop name
    [out] path - path to a local file
    */
void splitPropAndFile(WCHAR *in, WCHAR *&prop, WCHAR *&path)
{
    prop = new WCHAR[MAX_PATH];
    path = wcschr(in, '/')+1;
    wcscpy(prop, in);
    WCHAR *slash = wcschr(prop, '/');
    *slash = '\0';
}

MTPconnect::ERRORCODE handleCommand(char *in, LPWSTR parent, MTPconnect *mtp)
{
    if (mtp == 0)
        return MTPconnect::NULL_POINTER;

    char pre[4];
    char pathTmp[1024];
    char *tmp = strchr(in, ' ');
    unsigned int cmd = 0;

    // get the prefix
    strncpy(pre, in, tmp-in+1);
    pre[tmp-in+1] = '\0';
    cmd = atoi(pre);

    // get the path
    strncpy(pathTmp, tmp+1, 1024);
    int size = MultiByteToWideChar(CP_ACP, 0, pathTmp, -1, NULL, 0) * sizeof(wchar_t);
    WCHAR *path = new WCHAR[size];
    MultiByteToWideChar(CP_ACP, 0, pathTmp, -1, path, size);

    MTPconnect::ERRORCODE rc;
    int subcmd = 0;
    WCHAR *folder = NULL;
    WCHAR *file = NULL;
    WCHAR *fileNoPath = NULL;
    LPWSTR pFolder;
    switch (cmd)
    {
    case COMMAND:
        subcmd = _wtoi(path);
        if (subcmd == END_PROP)
        {
            printf("%d Writing data completed for current prop.\n", MTPconnect::M_IMPORTANT);
            printf("%d %d\n", MTPconnect::M_STATUS, END_PROP);
            fflush(stdout);
            state = state & (~IN_PROP);
            rc = MTPconnect::SUCCESS;
        }
        else if (subcmd == END_COPY)
        {
            printf("%d Finished saving to device\n", MTPconnect::M_IMPORTANT);
            printf("%d %d\n", MTPconnect::M_STATUS, END_COPY);
            fflush(stdout);
            rc = MTPconnect::SUCCESS;
        }
        else if (subcmd == QUIT)
        {
            printf("%d Closing...\n", MTPconnect::M_IMPORTANT);
            fflush(stdout);
            rc = MTPconnect::GUI_QUIT;
        }
        else if (subcmd == COPY)
        {
            printf("%d %d\n", MTPconnect::M_STATUS, COPY);
            fflush(stdout);
            rc = MTPconnect::SUCCESS;
        }
        else if (subcmd == DEV_DISCONNECT)
        {
            rc = MTPconnect::DISCONNECT;
        }
        else if (subcmd == TMP_XML_PATH)
        {
            printf("%d Searching for prop data on device\n", MTPconnect::M_INFO);
            WCHAR *tmpPath = mtp->getFile(arID);
            if (tmpPath != NULL)
            {
                printf("%d %d %ws\n", MTPconnect::M_STATUS, TMP_XML_PATH, tmpPath);
            }
            else
            {
                printf("%d No prop data found on device\n", MTPconnect::M_ERROR);
            }
            fflush(stdout);
            delete tmpPath;
            rc = MTPconnect::SUCCESS;
        }
        else if (subcmd == AUDIO_SCRIPT)
        {
            // subcmd = 9 folder/file
            // split folder and file into their own strings
            file = wcsrchr(path, '/')+1;
            folder = new WCHAR[MAX_PATH];
            wcscpy(folder, path+2);
            WCHAR *slash = wcsrchr(folder, '/');
            *slash = '\0';

            // get the directory for the audio script
            LPWSTR cwd = mtp->createDir(arID, folder);
            // try to copy the file from that directory
            LPWSTR audScrPath = mtp->getFile(cwd, file);
            if (audScrPath != NULL)
            {
                printf("%d %d %ws/%ws\n", MTPconnect::M_STATUS, AUDIO_SCRIPT, folder, audScrPath);
            }
            else
            {
                printf("%d Failed to retrieve main audio script for %ws\n", MTPconnect::M_ERROR, folder);
            }
            fflush(stdout);
            delete folder;
            rc = MTPconnect::SUCCESS;
        }
        else
            rc = MTPconnect::SUCCESS;
        break;
    case FILE_AUD:
        splitPropAndFile(path, folder, file);
        printf("%d Writing %ws to device for prop %ws.\n", MTPconnect::M_IMPORTANT, file, folder);
        fflush(stdout);
        pFolder = mtp->createDir(arID, folder);
        if (pFolder != NULL)
        {
            rc = mtp->writeFile(pFolder, file, MTPconnect::FT_AUD);
        }
        else
        {
            printf("%d Failed to set folder for prop (%ws) when attempting to copy file (%ws).\n", MTPconnect::M_ERROR, folder, file);
        }
        delete folder;
        break;
    case FILE_VID:
        splitPropAndFile(path, folder, file);
        printf("%d Writing %ws to device for prop %ws.\n", MTPconnect::M_IMPORTANT, file, folder);
        fflush(stdout);
        pFolder = mtp->createDir(arID, folder);
        if (pFolder != NULL)
        {
            rc = mtp->writeFile(pFolder, file, MTPconnect::FT_VID);
        }
        else
        {
            printf("%d Failed to set folder for prop (%ws) when attempting to copy file (%ws).\n", MTPconnect::M_ERROR, folder, file);
        }
        delete folder;
        break;
    case FILE_PIC:
        splitPropAndFile(path, folder, file);
        printf("%d Writing %ws to device for prop %ws.\n", MTPconnect::M_IMPORTANT, file, folder);
        fflush(stdout);
        pFolder = mtp->createDir(arID, folder);
        if (pFolder != NULL)
        {
            rc = mtp->writeFile(pFolder, file, MTPconnect::FT_PIC);
        }
        else
        {
            printf("%d Failed to set folder for prop (%ws) when attempting to copy file (%ws).\n", MTPconnect::M_ERROR, folder, file);
        }
        delete folder;
        break;
    case FILE_XML:
        // No need to split for xml, it is not under a prop
        printf("%d Writing %ws to device.\n", MTPconnect::M_IMPORTANT, path);
        fflush(stdout);
        if (mtp->checkExists(parent, L"artour.xml"))
        {
            printf("%d %d %d %ws\n", MTPconnect::M_STATUS, FILE_EXISTS, cmd, path);
            fflush(stdout);
            break;
        }
        rc = mtp->writeFile(parent, path, MTPconnect::FT_XML);
        break;
    case FILE_TXT:
        splitPropAndFile(path, folder, file);
        fileNoPath = wcsrchr(file, '/')+1;
        printf("%d Writing %ws to device for prop %ws.\n", MTPconnect::M_IMPORTANT, file, folder);
        fflush(stdout);
        pFolder = mtp->createDir(arID, folder);
        if (pFolder != NULL)
        {
            if (mtp->checkExists(pFolder, fileNoPath))
            {
                printf("%d %d %d %ws\n", MTPconnect::M_STATUS, FILE_EXISTS, cmd, path);
                fflush(stdout);
                delete folder;
                break;
            }
            rc = mtp->writeFile(pFolder, file, MTPconnect::FT_TXT);
        }
        else
        {
            printf("%d Failed to set folder for prop (%ws) when attempting to copy file (%ws).\n", MTPconnect::M_ERROR, folder, file);
        }
        delete folder;
        break;
    case PROP_NAME:
        printf("%d Creating directory for prop \"%ws\".\n", MTPconnect::M_IMPORTANT, path);
        fflush(stdout);
        state = state | IN_PROP;
        curPropID = mtp->createDir(parent, path);
        rc = MTPconnect::SUCCESS;
        break;
    case DELETE_FILE:
        // file - should be just a file name in this case (no path)
        splitPropAndFile(path, folder, file);
        if (wcscmp(folder, L".") == 0)
        {
            // trying to delete xml
            printf("%d Attempting to delete file \"%ws\" on device.\n", MTPconnect::M_INFO, L"artour.xml");
            fflush(stdout);
            rc = mtp->deleteObj(arID, L"artour.xml");
            if (rc == MTPconnect::NO_FILE_ERROR)
            {
                printf("%d Could not delete \"%ws\", not found.\n", MTPconnect::M_ERROR, L"artour.xml");
            }
            delete folder;
            break;
        }
        printf("%d Attempting to delete file \"%ws\" for prop \"%ws\" on device.\n", MTPconnect::M_INFO, file, folder);
        fflush(stdout);
        pFolder = mtp->createDir(arID, folder);
        if (pFolder != NULL)
        {
            rc = mtp->deleteObj(pFolder, file);
            if (rc == MTPconnect::NO_FILE_ERROR)
            {
                printf("%d Could not delete \"%ws\", not found.\n", MTPconnect::M_ERROR, file);
            }
        }
        else
        {
            printf("%d Failed to set folder for prop (%ws) when attempting to copy file (%ws).\n", MTPconnect::M_ERROR, folder, file);
        }
        delete folder;
        break;
    case DELETE_PROP:
        printf("%d Attempting to delete prop \"%ws\" from device.\n", MTPconnect::M_INFO, path);
        fflush(stdout);
        rc = mtp->deleteObj(arID, path, true);
        if (rc == MTPconnect::NO_FILE_ERROR)
        {
            printf("%d Could not delete \"%ws\", not found.\n", MTPconnect::M_ERROR, path);
        }
        break;
    case RENAME_PROP:
        // folder = old prop name
        // file = new prop name
        splitPropAndFile(path, folder, file);
        printf("%d Attempting to rename prop \"%ws\" to \"%ws\"\n", MTPconnect::M_INFO, folder, file);
        fflush(stdout);
        rc = mtp->renameFolderObj(arID, folder, file);
        break;
    case COPY_ALL_DATA:
        // just one arg here: the destination folder
        printf("%d Attempting to copy all prop data from the device to the local machine\n", MTPconnect::M_INFO);
        fflush(stdout);
        mtp->getRootFolder(arID, path);
        printf("%d %d", MTPconnect::M_STATUS, COPY_ALL_COMPLETE);
        fflush(stdout);
        rc = MTPconnect::SUCCESS;
        break;
    default:
        rc = MTPconnect::SUCCESS;
        break;
    }
    delete [] path;
    return rc;
}

int _tmain(int argc, _TCHAR* argv[])
{
    state = 0;
    HRESULT hr = S_OK;
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hr))
    {
        printf("%d Failed to init COM library, hr = 0x%lx\n", MTPconnect::M_ERROR, hr);
        return 1;
    }

    for (;;)
    {
        MTPconnect *mtp = new MTPconnect();

        while ((state & MTP_CONNECTED) != MTP_CONNECTED)
        {
            if (mtp->connect() == MTPconnect::CONNECT_SUCCESS)
            {
                printf("%d Successfully connected to device.\n", MTPconnect::M_INFO);
                printf("%d %d\n", MTPconnect::M_STATUS, DEV_CONNECT);
                fflush(stdout);
                state = state | MTP_CONNECTED;
            }
            else
            {
                printf("%d Failed to connect to Asus Transformer. Is it plugged in?\n", MTPconnect::M_ERROR);
                fflush(stdout);
                Sleep(5000);
                // Stupid hack
                // TODO: FIX YOUR DAMN CODE!!!
                delete mtp;
                mtp = new MTPconnect();
            }
        }

        arID = mtp->setDir(L"artour");

        char *buffer = new char[1024];
        for (;;)
        {
            memset(buffer, 0, 1024);
            std::cin.getline(buffer, 1024);
            if ((state & IN_PROP) == IN_PROP)
            {
                hr = handleCommand(buffer, curPropID, mtp);
            }
            else
            {
                hr = handleCommand(buffer, arID, mtp);
            }
            if (hr == MTPconnect::DISCONNECT)
            {
                state = state & (~IN_PROP);
                state = state & (~MTP_CONNECTED);
                delete mtp;
                delete buffer;
                break;
            }
            else if (hr == MTPconnect::GUI_QUIT)
                return 0;
        }
    }

	return 0;
}